package com.koron.sinoprobe.web.engineering.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.koron.bean.query.PageQuery;
import com.koron.common.core.interceptor.OrderByInterceptor;
import com.koron.sinoprobe.config.Constants;
import com.koron.sinoprobe.web.common.CommonUtils;
import com.koron.sinoprobe.web.engineering.bean.po.SpDivisionProject;
import com.koron.sinoprobe.web.engineering.bean.vo.SpDivisionProjectVO;
import com.koron.sinoprobe.web.engineering.excel.ExcelError;
import com.koron.sinoprobe.web.engineering.mapper.SpDivisionProjectMapper;
import com.koron.sinoprobe.web.engineering.service.SpDivisionProjectService;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目划分工程(SpDivisionProject)表服务实现类
 *
 * @author jzp
 * @since 2021-12-06 09:01:50
 */
@Service
public class SpDivisionProjectServiceImpl implements SpDivisionProjectService {

    /**
     * 通过ID查询单条数据
     */
    @Override
    @TaskAnnotation("getById")
    public SpDivisionProject getById(SessionFactory factory, String id) {
        SpDivisionProjectMapper mapper = factory.getMapper(SpDivisionProjectMapper.class);
        return mapper.selectById(id);
    }

    /**
     * 查询所有数据
     */
    @Override
    @TaskAnnotation("list")
    public List<SpDivisionProject> list(SessionFactory factory, SpDivisionProject spDivisionProject) {
        SpDivisionProjectMapper mapper = factory.getMapper(SpDivisionProjectMapper.class);
        return mapper.selectList(spDivisionProject);
    }

    @Override
    @TaskAnnotation("page")
    public PageInfo<SpDivisionProject> page(SessionFactory factory, PageQuery pageQuery, SpDivisionProject spDivisionProject) {
        OrderByInterceptor.setOrderBy(pageQuery.getOrders());            // 设置排序，若不设置排序，插件会因为没有排序字段而直接跳过，不会影响分页插件
        PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize());  //设置分页
        List<SpDivisionProject> spDivisionProjectList = list(factory, spDivisionProject);
        return new PageInfo<>(spDivisionProjectList);
    }

    @Override
    @TaskAnnotation("listByDivisionId")
    public List<SpDivisionProject> listByDivisionId(SessionFactory factory, String divisionId) {
        SpDivisionProject spDivisionProject = new SpDivisionProject();
        spDivisionProject.setDivisionId(divisionId);
        return this.list(factory, spDivisionProject);
    }

    /**
     * 拿到节点树
     */
    @Override
    @TaskAnnotation("treeByDivisionId")
    public List<SpDivisionProjectVO> treeByDivisionId(SessionFactory factory, String divisionId) {
        List<SpDivisionProject> spDivisionProjects = this.listByDivisionId(factory, divisionId);
        List<SpDivisionProjectVO> all = new ArrayList<>();
        if (CollectionUtils.isEmpty(spDivisionProjects)) {
            return all;
        }
        spDivisionProjects.forEach(e -> all.add(BeanUtil.toBean(e, SpDivisionProjectVO.class)));
        return CommonUtils.toTree(all, "0");
    }

    /**
     * 新增数据
     */
    @Override
    @TaskAnnotation("save")
    public boolean save(SessionFactory factory, SpDivisionProject spDivisionProject) {
        SpDivisionProjectMapper mapper = factory.getMapper(SpDivisionProjectMapper.class);
        return mapper.insertOrUpdate(spDivisionProject) > 0;
    }

    @Override
    @TaskAnnotation("saveTree")
    public boolean saveTree(SessionFactory factory, List<SpDivisionProjectVO> spDivisionProjectVOList) {
        List<SpDivisionProjectVO> saveData = spDivisionProjectVOList;
        // 1. 保存单位工程
        long count = saveData.stream().map(SpDivisionProjectVO::getName).distinct().count();
        Assert.state(saveData.size() == count, "单位工程不能重复");
        int i = 0;
        String divisionId = null;
        String projectId = null;
        for (SpDivisionProjectVO saveDatum : saveData) {
            if (divisionId == null) {
                divisionId = saveDatum.getDivisionId();
            }
            if (projectId == null) {
                projectId = saveDatum.getProjectId();
            }
            saveDatum.setType(Constants.SP_PROJECT_DIVISION_TYPE.PROJECT);
            saveDatum.setParentId("0");
            saveDatum.setSort(i++);
        }
        saveBatch(factory, saveData);

        // 2. 保存分部工程
        saveData = new ArrayList<>();
        for (SpDivisionProjectVO spDivisionProjectVO : spDivisionProjectVOList) {
            i = 0;
            for (SpDivisionProjectVO child : spDivisionProjectVO.getChildren()) {
                child.setDivisionId(divisionId);
                child.setProjectId(projectId);
                child.setParentId(spDivisionProjectVO.getId());
                child.setSort(i++);
                child.setType(Constants.SP_PROJECT_DIVISION_TYPE.SEGMENT);
                saveData.add(child);
            }
        }
        count = saveData.stream().map(SpDivisionProjectVO::getName).distinct().count();
        Assert.state(saveData.size() == count, "分部工程不能重复");
        saveBatch(factory, saveData);

        // 3. 保存单元工程
        saveData = new ArrayList<>();
        for (SpDivisionProjectVO spDivisionProjectVO : spDivisionProjectVOList) {
            for (SpDivisionProjectVO child : spDivisionProjectVO.getChildren()) {
                i = 0;
                for (SpDivisionProjectVO cell : child.getChildren()) {
                    cell.setDivisionId(divisionId);
                    cell.setProjectId(projectId);
                    cell.setParentId(child.getId());
                    cell.setSort(i++);
                    cell.setType(Constants.SP_PROJECT_DIVISION_TYPE.CELL);
                    saveData.add(cell);
                }
            }
        }
        count = saveData.stream().map(SpDivisionProjectVO::getName).distinct().count();
        Assert.state(saveData.size() == count, "单元工程不能重复");
        saveBatch(factory, saveData);
        return true;
    }

    @Override
    @TaskAnnotation("saveBatch")
    public boolean saveBatch(SessionFactory factory, List<SpDivisionProjectVO> lists) {
        if (CollectionUtils.isEmpty(lists)) {
            return false;
        }
        SpDivisionProjectMapper mapper = factory.getMapper(SpDivisionProjectMapper.class);
        return mapper.insertOrUpdateBatch(lists) > 0;
    }

    /**
     * 修改数据
     */
    @Override
    @TaskAnnotation("update")
    public boolean update(SessionFactory factory, SpDivisionProject spDivisionProject) {
        SpDivisionProjectMapper mapper = factory.getMapper(SpDivisionProjectMapper.class);
        return mapper.update(spDivisionProject) > 0;
    }

    /**
     * 通过主键删除数据
     */
    @Override
    @TaskAnnotation("deleteBatchIds")
    public boolean deleteBatchIds(SessionFactory factory, List<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return false;
        }
        SpDivisionProjectMapper mapper = factory.getMapper(SpDivisionProjectMapper.class);
        return mapper.deleteBatchIds(ids) > 0;
    }

    @Override
    @TaskAnnotation("removeByDivisionId")
    public boolean removeByDivisionId(SessionFactory factory, String divisionId) {
        if (StringUtils.isEmpty(divisionId)) {
            return false;
        }
        List<SpDivisionProject> spDivisionProjects = listByDivisionId(factory, divisionId);
        return deleteBatchIds(factory, spDivisionProjects.stream().map(SpDivisionProject::getId).collect(Collectors.toList()));
    }

    @Override
    public ExcelError readExcel(List<Map<Integer, String>> listMap, List<SpDivisionProjectVO> lists) {

        // 1. 空检测
        for (int i = 0; i < listMap.size(); i++) {
            for (int j = 0; j < 3; j++) {
                String s = listMap.get(i).get(j);
                if (StringUtils.isEmpty(s)) {
                    return new ExcelError(i, j, "不能为空");
                }
            }
        }

        // 2. 树构造
        Map<Integer, String> preMap = new HashMap<>(); // 上一行数据
        for (Map<Integer, String> integerStringMap : listMap) {
            // 2.1 设置单位工程
            // 2.1.1 拿第一列数据
            String projectName = integerStringMap.get(0);
            // 2.1.2 获取第二列的lists
            List<SpDivisionProjectVO> segLists = null;
            // 2.1.3 如果相同就合并
            if (projectName.equals(preMap.get(0))) {
                segLists = lists.get(lists.size() - 1).getChildren();
            } else {
                SpDivisionProjectVO spDivisionProjectVO = new SpDivisionProjectVO();
                spDivisionProjectVO.setName(projectName);
                segLists = new ArrayList<>();
                spDivisionProjectVO.setChildren(segLists);
                lists.add(spDivisionProjectVO);
            }

            // 2.2 设置分部工程
            // 2.2.1 拿第二列数据
            String segName = integerStringMap.get(1);
            // 2.2.2 获取第三列的lists
            List<SpDivisionProjectVO> cellLists = null;
            // 2.2.3 如果相同就合并
            if (projectName.equals(preMap.get(0)) && segName.equals(preMap.get(1))) {
                cellLists = segLists.get(segLists.size() - 1).getChildren();
            } else {
                SpDivisionProjectVO spDivisionProjectVO = new SpDivisionProjectVO();
                spDivisionProjectVO.setName(segName);
                cellLists = new ArrayList<>();
                spDivisionProjectVO.setChildren(cellLists);
                segLists.add(spDivisionProjectVO);
            }

            // 2.3 设置分部工程
            // 2.3.1 拿第三列数据
            String cellName = integerStringMap.get(2);
            // 2.3.3 如果相同就合并
            if (projectName.equals(preMap.get(0)) && segName.equals(preMap.get(1)) && cellName.equals(preMap.get(2))) {
                // do nothing
            } else {
                SpDivisionProjectVO spDivisionProjectVO = new SpDivisionProjectVO();
                spDivisionProjectVO.setName(cellName);
                cellLists.add(spDivisionProjectVO);
            }

            preMap = integerStringMap;
        }

        // 3. 重复数据检测
        Set<String> projectSet = new HashSet<>();
        for (int i = 0; i < lists.size(); i++) {
            // 单位工程检测
            SpDivisionProjectVO project = lists.get(i);
            if (projectSet.contains(project.getName())) {
                return new ExcelError(i, 0, "单位工程不能重复");
            }
            projectSet.add(project.getName());

            Set<String> segSet = new HashSet<>();
            List<SpDivisionProjectVO> segList = project.getChildren();
            for (int j = 0; j < segList.size(); j++) {
                // 分部工程检测
                SpDivisionProjectVO seg = segList.get(j);
                if (segSet.contains(seg.getName())) {
                    return new ExcelError(j, 1, "分部工程不能重复");
                }
                segSet.add(seg.getName());

                Set<String> cellSet = new HashSet<>();
                List<SpDivisionProjectVO> cellList = seg.getChildren();
                for (int k = 0; k < cellList.size(); k++) {
                    // 单元工程检测
                    SpDivisionProjectVO cell = cellList.get(k);
                    if (cellSet.contains(cell.getName())) {
                        return new ExcelError(k, 2, "单元工程不能重复");
                    }
                    cellSet.add(cell.getName());
                }
            }
        }

        return null;
    }

}
